;;;;;;;;;; drapieżnik!Bardzo, bardzo złe i tchórzliwe stworzenie.

; 1. Ucieka przed ochroną, no bo po co się narażać
; 2. Jak nie ucieknie, bo go podeszli, to zabija w obronie własnej
; 3. Zabija bystretkę roślinożerną, bo jest bezbronna, a on bezlitosny
; 4. Zjada robaki; bystretek nie je, zabija je dla zabawy


;------------------ Templejty ----------------------------------------------

(deftemplate visible (slot Object) (slot PosX) (slot PosY))
(deftemplate field (slot Type) (slot Resource) (slot PosX) (slot PosY))
(deftemplate move (slot Move) (slot MoveX) (slot MoveY))
(deftemplate stat (slot Name) (slot Value))

(deftemplate musiszJesc (slot Kiedy)) 
(deftemplate najlepszeZarcie (slot Resource) (slot PosX) (slot PosY))
;------------------ Templejty ----------------------------------------------

;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
;              UCIEKAMY PRZED MIĘSOŻERNĄ BYSTRETKĄ. A NUŻ NAS ZJE?
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------


; nie ma dokąd uciekać, trzeba się bronić ostatkiem sił

(defrule obronaWlasna
	(visible (Object BYSTRETKA_MIESOZERNA) (PosX ?x) (PosY ?y))
	(test (< (+ (* ?x ?x) (* ?y ?y) ) 2 )							; odległość x*x + y*y <2, jest za blisko
	)
	=>
	(assert (move (Move kill) (MoveX ?x) (MoveY ?y) ))				; trzeba ją ZABIĆ
	 (printout t zabija_w_obronie crlf) 
)

;---------------------------------------------------------------------------

; widzimy mięsożerną bystretkę, czas wiać

(defrule uciekajTchorzu

	(visible (Object BYSTRETKA_MIESOZERNA) (PosX ?x) (PosY ?y))				; Jeśli widać tego straszliwego potwora
	(test (< 																; Jeśli odległość jest mniejsza niż 4 (taka bezpieczna odległość :D )
		(+ (* ?x ?x) (* ?y ?y) )											; x*x + y*y < 4 
		4 )
	)
	=>
	(bind ?moveX 0)															
	(bind ?moveY 0)
	(if (< ?x 0) then														; decydujemy w którą stronę wiać
		(bind ?moveX 1) 
	)
	(if (> ?x 0) then
		(bind ?moveX -1) 
	)
	(if (< ?y 0) then
		(bind ?moveY 1) 
	)
	(if (> ?y 0) then
		(bind ?moveY -1) 
	)
	(if (<> ?moveX 0) then
		(bind ?moveY 0) 
	)
	(assert (move (Move move) (MoveX ?moveX) (MoveY ?moveY) ))
	 (printout t Drapieznik_ucieka! crlf) 
)

;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
;              DYBIEMY NA ŻYCIE ROŚLINOŻERNEJ BYSTRETKI
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------

(defrule atakujOfiare
	(visible (Object BYSTRETKA_ROSLINOZERNA) (PosX ?x) (PosY ?y))				; jeśli sąsiadujemy z tą bystretką to ja zabijemy, no bo co
	(test (< (+ (* ?x ?x) (* ?y ?y) ) 2 )										; nie będziemy jej zabijać na większą odległość, nie jesteśmy snajperem
	)
	=>
	(assert (move (Move kill) (MoveX ?x) (MoveY ?y) ))
	 (printout t zabija_ofiare crlf) 
)


;-----------------------------------------------------------------------------   
;-----------------------------------------------------------------------------
;					JEDZENIE ROBOKÓW, BO SĄ ŁATWE DO ZŁAPANIA
;-----------------------------------------------------------------------------   
;-----------------------------------------------------------------------------

;musi zacząć interesować się jedzeniem, jeśli ma mało zapasów(najedzenia)
 
 (defrule czyMusiJesc
 (stat (Name food) (Value ?v) )				; jeśli ma mniej niż 5 żarełka, to zaznacza, że musi jeść
	(test (< ?v 20))
	=>
	(bind ?kiedy (- ?v 1))
	(assert (musiszJesc (Kiedy ?kiedy))))
	
;-----------------------------------------------------------------------------

; koniecznie musi coś zjeść, jeśli jest osłabiony i akurat trafił na robaka
(defrule jedzNatychmiast
	(field (Type WORM) (Resource ?r) (PosX 0) (PosY 0))				; stoi na polu z robakiem i musi jeść natychmiast (kiedy==0)
 	(musiszJesc (Kiedy ?kiedy))
 	(test (< ?kiedy 5))
 	=>
 	(assert (move (Move collectWorm)(MoveX 0) (MoveY 0) )))
 	
;-----------------------------------------------------------------------------
; jeśli ma jeszcze troszkę zapasu, może iść szukać lepszych źródeł jedzenia

(defrule szukajDobregoJedzenia
  	(musiszJesc (Kiedy ?kiedy))			
  	(test (< ?kiedy 15)
  		)
  	=>
  	(assert (najlepszeZarcie (Resource 0) (PosX 0) (PosY 0))))

;-----------------------------------------------------------------------------
;

(defrule najlepszeZrodloJedzenia										; gniazdo roboków!
  	?gniazdo <- (field (Type WORM) (Resource ?r) (PosX ?x) (PosY ?y))
  	?najlepszy <-  (najlepszeZarcie  (Resource ?rB) (PosX ?xB) (PosY ?yB))
  	(test (< ?rB ?r))													;jeśli zasoby najlepszego sa mniejsze niż te w gnieździe
  	=>
  	(retract ?najlepszy)
  	(assert (najlepszeZarcie (Resource ?r) (PosX ?x) (PosY ?y))))		; ustawiamy, że najlepsze żarcie jest w aktualnym polu.
 
 ;----------------------------------------------------------------------------- 	
 
 ;;;; nasza bystretka stoi w punkcie 0,0. Naokoło ma punkty -1,0; 1,0; 0,-1; 0,1 ; -1,-1; -1,1; 1,-1; 1,1
 ;;;; poniższe dwie funkcje powodują przemieszczenie się do najlepszego miejsca z jedzeniem
 ;;;; zlokalizowanego w którymś z tych czterech punktów.
 ;;;; (test (> ?x ?y)) sprawdza czy x>y, czyli punkty 1,0,  0,1, 1,-1
 ;;;; (test (>= ?y ?x)) sprawdza y >=x, czyli  0,-1 ; -1,-1; -1,1; 1,1; 0,0
 ;;;; np jeśli x!=0 to  ( x / |x|) * (-1) dla ujemnych x pokazuje, że musimy iść o x=+1; dla dodatnich - o -1

 
 
    (defrule idzDoNajlepszegoX
  	(najlepszeZarcie (Resource ?r) (PosX ?x) (PosY ?y))					;sprawdzamy położenie najlepszego punktu z jedzeniem
  	(test (> ?x ?y))													; 
  	=>
  	(if (not (= ?x 0) ) then											; jeśli x jest rózny od 0
	(bind ?nowyX (* -1 (/ ?x (abs ?x))))								; nowy x ustawiamy na ( x / |x|) * (-1) - czyli 1 lub -1
	)
	(if (= ?x 0 ) then													; jeśli x=0, pozostaje 0
		(bind ?nowyX 0)
	)
    (assert (move (Move move)(MoveX ?nowyX) (MoveY 0) )))
 
 ;-----------------------------------------------------------------------------   
    (defrule idDoNajlepszegoY
  	(najlepszeZarcie (Resource ?r) (PosX ?x) (PosY ?y))
  	(test (>= ?y ?x))
  	=>
	(if (not (= ?y 0) ) then
	(bind ?nowyY (* -1 (/ ?y (abs ?y))))
	)
	(if (= ?y 0) then
		(bind ?nowyY 0)
	)
    (assert (move (Move move)(MoveX 0) (MoveY ?nowyY) )))





